﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

namespace thailandProject.Models
{
    public class ReservationProperty
    {
        public RESERVATION reservation;
        public PROPERTY property;
        public ReservationProperty nextPartial = null; //Links to the next partial match, if any
    }
    
    public class ClientReservation
    {
        public CLIENT client;
        public List<ReservationProperty> reservations = new List<ReservationProperty>();
        public List<TASK> clientTasks = new List<TASK>();
        public decimal quotedPrice = 0; //The total price of the reservation.
        public decimal amountPaid = 0; //The amount this guest has paid towards this reservation
        public decimal balanceDue = 0; //quotedPrice - amountPaid

        /// <summary>
        /// Gets the client's information and all upcoming reservations that the client
        /// has.
        /// </summary>
        /// <param name="clientID">database id of the client</param>
        /// <returns>A ClientReservation object containing upcoming reservations and the client's details</returns>
        public static ClientReservation getClientDetails(int clientID)
        {
            ClientReservation rt = new ClientReservation();

            try
            {
                using (ThailandEntities a = new ThailandEntities())
                {
                    //Fetch the client with the id of clientID
                    var clients = from client in a.CLIENTs
                                  where clientID == client.clientID
                                  select client;
                    rt.client = clients.ToList()[0];

                    //Fetch all upcoming reservations (if the end date of the res is after DateTime.Now)
                    DateTime now = DateTime.Now.Date;
                    var reservations = from reservation in a.RESERVATIONs
                                       from property in a.PROPERTies
                                       where reservation.propID == property.propID &&
                                       clientID == reservation.clientID &&
                                       reservation.resEndDate >= now
                                       orderby reservation.resStartDate
                                       select reservation;

                    List<RESERVATION> res = reservations.ToList();
                    foreach (RESERVATION r in res)
                    {
                        ReservationProperty rp = new ReservationProperty();
                        rp.reservation = r;
                        rp.property = r.PROPERTY;
                        if(!r.resIsHeld) //Don't add in a price if it's not confirmed
                            rt.quotedPrice += r.resQuotedPrice;
                        rt.reservations.Add(rp);
                    }

                    //Scan through all the returns reservations to see if any are partial matches
                    //Partial matches will have one reservation end when a new one begins
                    for (int i = 0; i < rt.reservations.Count - 1; i++) //-1 because the last reservation can't have something come after it
                    {
                        if (rt.reservations[i].reservation.resEndDate == rt.reservations[i + 1].reservation.resStartDate)
                            rt.reservations[i].nextPartial = rt.reservations[i + 1];
                    }

                    //Fetch the payment history for the current reservations
                    var payments = from payment in a.PAYMENTs
                                   from reservation in a.RESERVATIONs
                                   where payment.resID == reservation.resID &&
                                   clientID == reservation.clientID &&
                                   reservation.resEndDate >= now
                                   select payment;
                    List<PAYMENT> pay = payments.ToList();

                    foreach (PAYMENT p in pay)
                        rt.amountPaid += p.paymentAmount;

                    rt.balanceDue = rt.quotedPrice - rt.amountPaid;

                    //Fetch any important pickup/dropoffs (e.g. Airport)
                    //Select all taskdetails which belong to an upcoming reservation where each taskdetail
                    //has three pairs against a task.

                    /* var taskdetails = from taskdetail in a.TASKDETAILs
                                       from task in a.TASKs
                                       from reservation in a.RESERVATIONs
                                       where taskdetail.taskID == task.taskID &&
                                       task.resID == reservation.resID &&
                                       reservation.resEndDate >= now &&
                                       (from taskdetail2 in a.TASKDETAILs
                                       where taskdetail2.taskID == task.taskID
                                       select taskdetail2).Count() == 3
                                       orderby taskdetail.TASK.taskTypeID
                                       select taskdetail;
                     */

                    var taskdetails = from task in a.TASKs
                                      from reservation in a.RESERVATIONs
                                      from client in a.CLIENTs
                                      where task.resID == reservation.resID &&
                                      reservation.clientID == client.clientID &&
                                      client.clientID == clientID &&
                                      task.taskDueDate >= now
                                      orderby task.taskDueDate
                                      select task;

                    rt.clientTasks = taskdetails.ToList();
                }
            }
            catch (Exception ex)
            {
                ErrorLog.logError(ex);
            }

            return rt;
        }
    }
}